import os.path
import pathlib
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support import expected_conditions as EC
import pyautogui
from utils.log_handler import logger


# 页面类
class BasePage:
    screen_shoot_path = pathlib.Path(__file__).parent.parent / "screens"

    def __init__(self, driver):
        self.driver = driver
        self.driver.maximize_window()
        self.wait = WebDriverWait(self.driver, 5, poll_frequency=0.5)

    def open(self, url, desc):
        logger.info(f"打开{desc}url：{url}")
        self.driver.get(url)

    def get_title(self):
        logger.info(f"获取当前窗口标题：{self.driver.title}")
        return self.driver.title

    def get_current_url(self):
        logger.info(f"获取当前窗口标题：{self.driver.current_url}")
        return self.driver.current_url

    def refresh(self):
        logger.info("刷新当前页面")
        self.driver.refresh()

    def go_back(self):
        logger.info("返回当前页之前页面")
        self.driver.back()

    def go_forward(self):
        logger.info("返回当前页之后页面")
        self.driver.forward()

    def scroll_to_top(self):
        logger.info("上拉到页面顶部")
        self.driver.execute_script("window.scrollTo(0, 0)")

    def scroll_to_bottom(self):
        logger.info("上拉到页面底部")
        self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")

    def scroll_to_element(self, element: WebElement):
        logger.info(f"将页面滚到'{element}'位置")
        self.driver.execute_script("arguments[0].scrollIntoView();", element)

    def wait_for_element(self, locator: tuple):
        try:
            return self.wait.until(EC.presence_of_element_located(locator))
        except TimeoutException as e:
            logger.exception(f"定位器：'{locator[1]}'定位失败，原因：{e}")

    def wait_for_visible_element(self, locator: tuple):
        try:
            return self.wait.until(EC.visibility_of_element_located(locator))
        except TimeoutException as e:
            logger.exception(f"定位器：'{locator[1]}'定位不可见，原因：{e}")

    def wait_for_invisible_element(self, locator: tuple):
        try:
            return self.wait.until(EC.invisibility_of_element_located(locator))
        except TimeoutException as e:
            logger.exception(f"定位器：'{locator[1]}'未消失，原因：{e}")

    def wait_for_alert(self):
        try:
            logger.info(f"alert弹窗出现")
            return self.wait.until(EC.alert_is_present())
        except TimeoutException as e:
            logger.exception(f"alert弹窗未出现，原因：{e}")

    def click(self, locator: tuple, desc=None):
        element = self.wait_for_element(locator)
        if element:
            if desc:
                logger.info(f"点击{desc}")
            element.click()

    def double_click(self, locator: tuple, desc):
        element = self.wait_for_element(locator)
        if element:
            logger.info(f"双击{desc}")
            ActionChains(self.driver).double_click(element).perform()

    def right_click(self, locator: tuple, desc):
        element = self.wait_for_element(locator)
        if element:
            logger.info(f"右击{desc}")
            ActionChains(self.driver).context_click(element).perform()

    def hover(self, locator: tuple, desc):
        element = self.wait_for_element(locator)
        if element:
            logger.info(f"鼠标悬浮到{desc}")
            ActionChains(self.driver).move_to_element(element).perform()

    def fill(self, locator: tuple, value: str, desc):
        element = self.wait_for_element(locator)
        if element:
            try:
                element.clear()
                element.send_keys(value)
                logger.info(f"清空{desc}输入框并输入：{value}")
            except Exception as e:
                logger.info(f"{desc}输入框输入：{value}")
                element.send_keys(value)

    def clear(self, locator: tuple):
        element = self.wait_for_element(locator)
        if element:
            element.clear()

    def select_option_by_value(self, locator: tuple, value: str):
        element = self.wait_for_element(locator)
        if element:
            options = element.find_elements('tag name', 'option')
            for option in options:
                if option.get_attribute('value') == value:
                    option.click()
                    return option.is_selected()

    def select_option_by_label(self, locator: tuple, label: str):
        element = self.wait_for_element(locator)
        if element:
            options = element.find_elements('tag name', 'option')
            for option in options:
                if option.text.strip() == label:
                    option.click()
                    return option.is_selected()

    def get_selected_option(self, locator: tuple):
        element = self.wait_for_element(locator)
        if element:
            selected_option = element.find_element("css selector", 'option:checked')
            return {"value": selected_option.get_attribute('value'), "label": selected_option.text.strip()}

    def get_all_options(self, locator: tuple):
        element = self.wait_for_element(locator)
        if element:
            options = element.find_elements('tag name', 'option')
            return [{"value": option.get_attribute('value'), "label": option.text.strip()} for option in options]

    def get_attribute_value(self, locator: tuple, attribute: str, desc):
        element = self.wait_for_element(locator)
        if element:
            if not attribute:
                logger.info("指定attribute值为空，返回None")
                return
            try:
                value = element.get_attribute(attribute)
                logger.info(f"获取{desc}{attribute}属性值：{value}")
                return value
            except Exception as e:
                logger.exception(f"获取{desc}{attribute}属性值失败，失败原因：{e}")

    def get_text(self, locator: tuple, desc):
        element = self.wait_for_element(locator)
        if element:
            try:
                value = element.text.strip()
                logger.info(f"获取{desc}值：{value}")
                return value
            except Exception as e:
                logger.exception(f"获取{desc}值失败，失败原因：{e}")

    def get_value(self, locator: tuple, desc):
        element = self.wait_for_element(locator)
        if element:
            try:
                value = element.get_attribute('value')
                logger.info(f"获取{desc}value值：{value}")
                return value
            except Exception as e:
                logger.exception(f"获取{desc}value值失败，失败原因：{e}")

    def get_element_count(self, locator: tuple, desc):
        count = len(self.driver.find_elements(*locator))
        logger.info(f"获取{desc}个数：{count}")
        return count

    def is_element_present(self, locator: tuple, desc):
        flag = len(self.driver.find_elements(*locator)) > 0
        logger.info(f"{desc}是否存在：{flag}")
        return flag

    def is_element_visible(self, locator: tuple, desc):
        try:
            flag = self.driver.find_element(*locator).is_enabled()
            logger.info(f"{desc}是否可见：{flag}")
            return flag
        except Exception as e:
            logger.exception(f"定位失败，失败原因：{e}")

    def is_element_enabled(self, locator: tuple, desc):
        try:
            flag = self.driver.find_element(*locator).is_enabled()
            logger.info(f"{desc}是否可用：{flag}")
            return flag
        except Exception as e:
            logger.exception(f"定位失败，失败原因：{e}")

    def set_input_file(self, locator: tuple, file_path: str):
        try:
            element = self.wait_for_element(locator)
            logger.info(f"上传文件：'{file_path}'")
            element.send_keys(file_path)
            return True
        except Exception as e:
            logger.exception(f"文件上传失败，失败原因：{e}")

    def set_upload_file(self, locator: tuple, file_path: str):
        try:
            self.click(locator)
            logger.info("点击上传按钮")
            logger.info(f"上传文件：'{file_path}'")
            pyautogui.write(file_path)
            logger.info("点击enter按钮")
            pyautogui.press("enter")
            logger.info("点击enter按钮")
            pyautogui.press("enter")
            return True
        except Exception as e:
            logger.exception(f"文件上传失败，失败原因：{e}")

    def set_window_size(self, width: int, height: int):
        try:
            logger.info(f"设置窗口大小为宽：{width}，高：{height}")
            self.driver.set_window_size(width, height)
            return True
        except Exception as e:
            logger.exception(f"设置窗口大小失败，失败原因：{e}")

    def take_screenshot(self, file_name, page_name):
        try:
            page_path = self.screen_shoot_path / page_name
            if not os.path.exists(page_path):
                os.makedirs(page_path)
            file_path = page_path / f"{file_name}.png"
            logger.info(f"保存图片'{file_name}'")
            self.driver.save_screenshot(file_path)
            return True
        except Exception as e:
            logger.exception(f"图片'{file_name}'保存失败，原因：{e}")

    def switch_to_alert(self):
        try:
            logger.info("处理alert弹窗")
            alert = self.driver.switch_to.alert
            alert.dismiss()
            return True
        except Exception as e:
            logger.exception(f"弹窗处理失败，失败原因：{e}")

    def switch_to_iframe(self, locator: tuple, desc):
        try:
            logger.info(f"切换到{desc}iframe")
            iframe = self.wait_for_element(locator)
            self.driver.switch_to.frame(iframe)
        except Exception as e:
            logger.exception(f"切换到{desc}iframe失败，失败原因：{e}")

    def switch_to_main(self):
        try:
            logger.info("切换到主页面")
            self.driver.switch_to.default_content()
            return True
        except Exception as e:
            logger.exception(f"切换到主页面失败，失败原因：{e}")

    def switch_to_new_window(self):
        try:
            logger.info("切换到新窗口")
            self.driver.switch_to.window(self.driver.window_handles[-1])
            return True
        except Exception as e:
            logger.exception(f"切换到新窗口失败，失败原因：{e}")

    def close(self):
        try:
            logger.info("退出浏览器")
            self.driver.quit()
        except Exception as e:
            logger.exception(f"退出浏览器失败，失败原因：{e}")
